파이썬 자료구조(튜플, 리스트, 딕셔너리)

튜플(Tuple)

튜플은 1차원의 고정된 크기를 가지는 변경이 불가능한 순차 자료형이다. 튜플을 생성하는 가장 쉬운 방법은 쉼표로 구분된 값을 대입하거나, 괄호를 사용해서 값을 묶어줌으로써 중첩된 튜플을 정의할 수 있다.

선언 및 값 할당

tup = tuple() # tuple init.
tup = () # tuple init.
tup = 4, 5, 6
tup = (4, 5, 6)
print(tup) # (4, 5, 6)

nested_tup = (4, 5, 6), (7,8)
print(nested_tup) # ((4, 5, 6), (7, 8))

형변환 및 원소 접근

모든 순차 자료형이나 이터레이터는 tuple 메소드를 통해 튜플로 변환할 수 있다. 또한, 튜플의 각 원소는 대괄호 []를 이용해서 다른 순차 자료형처럼 접근할 수 있다.

tuple([4, 0, 2]) # (4, 0, 2)
tup = tuple('string')
print(tup) # ('s', 't', 'r', 'i', 'n', 'g')e
print(tup[0]) # 's'

튜플에서 값 분리하기

파이썬은 튜플과 같은 표현의 변수에 튜플을 대입하면 등호(=) 오른쪽에 있는 변수에서 값을 분리한다.

tup = (4, 5, 6)
a, b, c = tup
print(a, b) # 4 5

tup = 4, 5, (6, 7)
a, b, (c, d) = tup
print(c, d) # 6 7

tmp = a
a = b
b = tmp
b, a = a, b
seq = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
for a, b, c in seq:
pass

튜플 메소드

튜플의 크기와 내용은 변경이 불가하므로 인스턴스 메소드가 많지 않다. 유용하게 사용되는 메소드 중 하나는 주어진 값과 같은 값이 몇 개나 있는지 반환하는 count 메소드다.

a = (1, 2, 2, 2, 3, 4, 2)
print(a.count(2)) # 4

튜플 이어붙이기 및 반복하기

튜플에도 + 연산자나 * 연산자를 사용할 수 있다.

tup1 = (4, None, 'foo') + (6, 0) + ('bar',)
print(tup1) # (4, None, 'foo', 6, 0, 'bar')

tup2 = ('foo', 'bar') * 3
print(tup2) # ('foo', 'bar', 'foo', 'bar', 'foo', 'bar')


리스트(List)

튜플과는 대조적으로 리스트는 크기나 내용의 변경이 가능하다. 리스트는 대괄호 []list() 함수를 사용해서 생성할 수 있다.

선언 및 값 할당

a_list = list() # init.
a_list = [] # init.
a_list = [2, 3, 7, None]
print(a_list) # [2, 3, 7, None]

형변환 및 원소 접근

tup = ('foo', 'bar', 'baz')
b_list = list(tup)
print(b_list) # ['foo', 'bar', 'baz']
b_list[1] = 'peekaboo'
print(b_list) # ['foo', 'peekaboo', 'baz']

원소 추가 및 삭제하기

append() 메소드를 사용해서 리스트의 끝에 새 값을 추가할 수 있다.

b_list.append('dwarf')
print(b_list) # ['foo', 'peekaboo', 'baz', 'dwarf']

insert() 메소드를 사용하면 리스트의 특정 위치에 값을 추가할 수 있다. 단, insert는 추가된 값 이후의 값을 모두 이동시켜야 하므로 append에 비해 연산 비용이 많이 든다.

b_list.insert(1, 'red')
print(b_list)

pop() 메소드는 특정 위치에서 값을 반환하고 해당 값을 리스트에서 삭제한다. remove 메소드를 이용해서 원소를 삭제할 수 있는데, 삭제는 리스트 제일 앞에 위치한 값 부터 이루어진다.

print(b_list.pop(2)) # peekaboo
print(b_list) # ['foo', 'red', 'baz', 'dwarf']

b_list.append('foo')
b_list.remove('foo')
print(b_list) # ['red', 'baz', 'dwarf', 'foo']

in 예약어를 사용해서 리스트에 어떤 값이 있는지 검사할 수 있다.

print('dwarf' in b_list) # True

리스트 이어붙이기

튜플과 마찬가지로 + 연산자를 이용하면 두 개의 리스트를 합칠 수 있다. + 연산자 외에도 extend() 메소드를 통해 여러 값을 추가할 수 있다.

c_list = [4, None, 'foo'] + [7, 8, (2, 3)]
print(c_list) # [4, None, 'foo', 7, 8, (2, 3)]

d_list = [4, None, 'foo']
d_list.extend([7, 8, (2, 3)])
print(d_list) # [4, None, 'foo', 7, 8, (2, 3)]

리스트 정렬

sort() 함수를 이용해서 새로운 리스트를 생성하지 않고 그대로 리스트를 정렬할 수 있다. 매개변수로 key 값을 주면 정렬기준으로 사용할 값을 선택할 수 있으며, 매개변수에 reverse값을 사용하면 정렬 결과를 내림차순으로 변경할 수 있다.

a = [7, 2, 5, 1, 3]
a.sort()
print(a) # [1, 2, 3, 5, 7]

a.sort(reverse=True)
print(a) # [7, 5, 3, 2, 1]

b = ['saw', 'small', 'He', 'foxes', 'six']
b.sort(key=len)
print(b) # ['He', 'saw', 'six', 'small', 'foxes']

리스트 컴프리헨션

리스트 컴프리헨션(List Comprehension)를 이용하면 간결한 표현으로 새로운 리스트를 만들 수 있다. 기본 형태는 다음과 같다.

list_comp = [expr for val in collection if condition]
strings = ['a', 'as', 'bat', 'car', 'dove', 'python']
result = [x.upper() for x in strings if len(x) > 2]
print(result) # ['BAT', 'CAR', 'DOVE', 'PYTHON']


딕셔너리(Dict)

딕셔너리는 파이썬 내장 자료 구조 중 가장 중요한 자료구조다. 딕셔너리는 유연한 크기를 가지는 key:value 쌍으로, 딕셔너리를 생성하는 방법은 중괄호 {}를 사용하여 콜론으로 구분된 key와 value를 둘러싸는 것이다.

유효한 Key

딕셔너리의 value는 어떤 파이썬 객체라도 사용할 수 있지만 key는 스칼라형(정수, 실수, 문자열)이나 튜플처럼 값이 바뀌지 않는 객체만 사용할 수 있다. 기술적으로는 해시가 가능해야 한다는 뜻이며, hash 함수를 사용해서 검사할 수 있다.

print(hash('string')) # 8170251618896179612
print(hash((1, 2, (2, 3)))) # -9209053662355515447
print(hash((1, 2, [2, 3]))) # 리스트는 딕셔너리의 key값에 사용 불가

선언 및 값 할당

empty_dict = {}
d1 = {'a':'some value', 'b':[1,2,3,4]}
print(d1) # {'a': 'some value', 'b': [1, 2, 3, 4]}

원소 접근 및 값입력

리스트나 튜플을 사용하는 것처럼 사전의 값에 접근하거나 값을 입력할 수 있다.

d1[7] = 'an integer'
print(d1) # {'a': 'some value', 'b': [1, 2, 3, 4], 7: 'an integer'}
print(d1['b']) # [1, 2, 3, 4]

딕셔너리에 어떤 key가 있는지 확인하는 것도 리스트나 튜플처럼 in 예약어를 사용하여 확인할 수 있다.

print('b' in d1) # True

keys() 메소드와 values() 메소드는 각각 key와 value가 담긴 이터레이터를 반환한다. items() 메소드는 key와 value가 같이 담긴 이터레이터를 반환한다.

print(d1.keys()) # dict_keys(['a', 'b', 7])
print(d1.values()) # dict_values(['some value', [1, 2, 3, 4], 'an integer'])
for key, value in d1.items():
print(key, value) # a some value ...

딕셔너리의 get() 메소드는 아래 if-else 구문을 한 줄로 대체할 수 있다.

if key in some_list:
value = some_dict[key]
else:
value = default_value

value = some_dict.get(key, default_value)

여러 단어를 시작 글자에 따라 딕셔너리에 리스트 형태로 저장하는 코드는 다음과 같다.

words = ['apple', 'bat', 'bar', 'atom', 'book']
by_letter = {}
for word in words:
letter = word[0]
if letter not in by_letter:
by_letter[word] = [word]
else:
by_letter[letter].append(word)

print(by_letter) # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']}

원소 삭제하기

del 예약어나 pop() 메소드를 사용해 딕셔너리의 값을 삭제할 수 있다.

d1[5] = 'some value'
del d1[5]

d1['dummy'] = 'another value'
ret = d1.pop('dummy')
print(ret) # another value

순차 자료구조로부터 딕셔너리 생성하기

zip() 메소드를 사용하면 두 개의 순차 자료구조의 각 원소를 짝지어서 딕셔너리를 만들 수 있다.

mapping = {}
for key, value in zip(key_list, value_list):
mapping[key] = value

mapping = dict(zip(range(5), reversed(range(5))))
print(mapping) # {0: 4, 1: 3, 2: 2, 3: 1, 4: 0}

딕셔너리 컴프리헨션

딕셔너리에 대해서도 리스트 컴프리헨션과 같은 방식을 적용할 수 있다.

dict_comp = {key-expr : value-expr for value in collection if condition}
strings = ['a', 'as', 'bat', 'car', 'dove', 'python']
loc_mapping = {val : index for index, val in enumerate(strings)}
print(loc_mapping) # {'a': 0, 'as': 1, 'bat': 2, 'car': 3, 'dove': 4, 'python': 5}
loc_mapping = dict((val, idx) for idx, val in enumerate(strings))
print(loc_mapping) # {'a': 0, 'as': 1, 'bat': 2, 'car': 3, 'dove': 4, 'python': 5}
Share